﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace KOPLibrary.DataManagement
{
    public class AbstractData : List<DataEntity>, ITypedList
    {
        private List<string> columns = null;


        public List<string> Columns
        {
            get
            {
                if (columns == null)
                    columns = new List<string>();
                return columns;
            }
        }

        public List<object[]> ItemArray
        {
            get
            {
                return this.Select(p => p.value).ToList();
            }
        }



        public string Eval(int row, string column)
        {
            
            if (Columns.IndexOf(column) < 0)
                return "!HATA!";
            else
            {
                object value = this[row].value[Columns.IndexOf(column)];
                return value == null ? string.Empty: value.ToString();
            }
        }


        public void Add(object[] row)
        {
            DataEntity entity = new DataEntity(row, this, this.Count);
            this.Add(entity);
        }

        #region ITypedList Members

        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
        {
            return TypeDescriptor.GetProperties(this[0]);

        }

        public string GetListName(PropertyDescriptor[] listAccessors)
        {
            return "AsbtractData";
        }

        #endregion

        public static readonly string FieldRegEx = @"(?:\{#)([^.*#\}]+)(?![#\}])";

        

        internal List<string> BindableFields(string expression)
        {
            MatchCollection fieldMatches = Regex.Matches(expression, FieldRegEx);
            List<string> result = new List<string>();
            foreach (Match m in fieldMatches)
            {
                string fieldName = m.ToString().Replace("{#", "").Replace("#}", "");
                result.Add(fieldName);
            }
            return result;
        }

        internal string Bind(int row, string expression)
        {
            return Bind(row, expression, BindableFields(expression));
        }

        public static string Qualify(string fieldName)
        {
            return "{#" + fieldName + " #}";
        }

        

        internal string Bind(int row, string expression, List<string> fields)
        {

            if (string.IsNullOrEmpty(expression.Trim()))
                return "";
            else
            {
                StringBuilder sb = new StringBuilder(expression);
                //MatchCollection fieldMatches = Regex.Matches(expression, FieldRegEx);
                foreach (string fieldName in fields)
                {
                    string fieldNameCorrected = fieldName.Replace("\r\n", " ");
                    string fieldValue = Eval(row, fieldNameCorrected);
                    sb.Replace(Qualify(fieldNameCorrected), fieldValue);
                }
                return sb.ToString();
            }
        }

        internal void CreateTemplateData()
        {
            List<object> tempdata = new List<object>();
            foreach (string col in this.Columns)
                tempdata.Add(AbstractData.Qualify(col));
            Add(tempdata.ToArray());
        }
    }

    public class AbstractDataItemPropertyDescriptor : PropertyDescriptor
    {
        private AbstractData data;
        private int colIndex;

        public AbstractDataItemPropertyDescriptor(int colIndex, AbstractData data)
            : base(data.Columns[colIndex], new Attribute[] { })
        {
            this.data = data;
            this.colIndex = colIndex;
        }

        public override bool CanResetValue(object component)
        {
            return false;
        }

        public override Type ComponentType
        {
            get { return typeof(object); }
        }

        public override object GetValue(object component)
        {
            return ((DataEntity)component).value[colIndex];
        }

        public override bool IsReadOnly
        {
            get { return true; }
        }

        public override Type PropertyType
        {
            get { return typeof(object); }
        }

        public override void ResetValue(object component)
        {

        }

        public override void SetValue(object component, object value)
        {

        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }

    public class DataEntity : ICustomTypeDescriptor
    {
        internal object[] value;
        internal AbstractData owner;
        internal int rowIndex;
        public bool Selected { get; set; }

        internal DataEntity(object[] value, AbstractData owner, int rowIndex)
        {
            this.value = value;
            this.owner = owner;
            this.rowIndex = rowIndex;
            Selected = true;
        }

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return AttributeCollection.Empty;
        }

        public string GetClassName()
        {
            return "Measurement.View";
        }

        public string GetComponentName()
        {
            return "";
        }

        public TypeConverter GetConverter()
        {
            return new TypeConverter();
        }

        public EventDescriptor GetDefaultEvent()
        {
            return null;
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }

        public object GetEditor(Type editorBaseType)
        {
            return null;
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return EventDescriptorCollection.Empty;
        }

        public EventDescriptorCollection GetEvents()
        {
            return EventDescriptorCollection.Empty;
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetProperties();
        }

        public PropertyDescriptorCollection GetProperties()
        {
            List<PropertyDescriptor> list = new List<PropertyDescriptor>();
            for (int i = 0; i < this.owner.Columns.Count; i++)
            {
                PropertyDescriptor desc = new AbstractDataItemPropertyDescriptor(i, owner);
                list.Add(desc);
            }
            return new PropertyDescriptorCollection(list.ToArray());
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion
    }
}
